package com.iwhalecloud.bss.kite.cucc.order.service;

import com.alibaba.fastjson.JSON;
import com.iwhalecloud.bss.kite.client.api.scene.operate.ITraceOperateService;
import com.iwhalecloud.bss.kite.client.dto.order.OrderCommitRequestDTO;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.constant.TableConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.SeqUtils;
import com.iwhalecloud.bss.kite.common.util.TransactionIdUtils;
import com.iwhalecloud.bss.kite.cucc.order.accept.process.OrderBusinessFactory;
import com.iwhalecloud.bss.kite.cucc.order.cache.OrderRequestCache;
import com.iwhalecloud.bss.kite.cucc.order.util.SceneInstMergeUtils;
import com.iwhalecloud.bss.kite.dataservice.cache.DcSystemParamCache;
import com.iwhalecloud.bss.kite.dataservice.entity.KiteOrderAcceptLog;
import com.iwhalecloud.bss.kite.dataservice.mapper.other.KiteOrderAcceptLogMapper;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.order.client.api.operate.IKiteOrderAcceptService;
import com.iwhalecloud.bss.kite.order.client.context.OrderContext;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequest;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequestLog;
import com.ztesoft.bss.common.bo.SimpleLoginInfo;
import com.ztesoft.bss.common.exception.BssException;
import com.ztesoft.bss.common.util.ContextUtil;
import com.ztesoft.bss.common.util.SpringUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * <Description> <br>
 * 转单新流程服务
 *
 * @author xiao.xuzhang<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2020年2月12日 <br>
 * @since R9.0<br>
 * @see com.iwhalecloud.bss.kite.cucc.order.service <br>
 */

@Service
public class KiteOrderAcceptService implements IKiteOrderAcceptService {

    @Resource
    private IOperateSceneInstService operateSceneInstService;

    @Resource
    private IQuerySceneInstService querySceneInstService;

    @Resource
    private ITraceOperateService traceOperateService;

    @Override
    public void preCheck(OrderCommitRequestDTO request) {
        checkOrderCommitRequest(request);
        // 场景分组合并计算处理
        request.setPreCheck(true);
        List<OrderRequest> orderRequests = SceneInstMergeUtils.sceneInstsCompute(request);
        for (OrderRequest orderRequest : orderRequests) {
            orderRequest.setPreCheck(true);
            // 设置订单请求对象到上下文
            OrderContext.init(orderRequest);

            // 调度转单流程
            doHandle(orderRequest);
        }
    }

    @Override
    public void submit(OrderCommitRequestDTO request) {
        checkOrderCommitRequest(request);
        // 场景分组合并计算处理
        List<OrderRequest> orderRequests = SceneInstMergeUtils.sceneInstsCompute(request);
        for (OrderRequest orderRequest : orderRequests) {
            // 订单预校验流程生成的OrderRequest
            OrderRequest preOrderRequest = OrderRequestCache.get(orderRequest.getCustOrderId());
            if (Objects.nonNull(preOrderRequest)) {
                preOrderRequest.setHandlerClassNames(new ArrayList<>());
                preOrderRequest.setPreCheck(false);
                preOrderRequest.setAbort(null);
            }
            else {
                preOrderRequest = orderRequest;
                preOrderRequest.setPreCheck(null);
            }

            // 设置订单请求对象到上下文
            OrderContext.init(preOrderRequest);

            // BO端到端埋点
            //traceOperateService.traceSummit(preOrderRequest.getMainSceneInstId());

            // 调度转单流程
            doHandle(preOrderRequest);
        }

        // 清空场景实例缓存
        deleteSceneInsts(orderRequests);
    }

    /**
     * 调度转单流程
     * @param orderRequest
     */
    private void doHandle(OrderRequest orderRequest) {
        KiteOrderAcceptLog kiteOrderAcceptLog = new KiteOrderAcceptLog();
        try {
            kiteOrderAcceptLog.setReqTime(LocalDateTime.now());
            kiteOrderAcceptLog.setResultCode(KeyConsts.SUCCESS_0);
            kiteOrderAcceptLog.setTransactionId(TransactionIdUtils.getTransactionIdOrRandom());

            if (Objects.nonNull(orderRequest) && CollectionUtils.isNotEmpty(orderRequest.getSceneInstIds())) {
                for (String sceneInstId : orderRequest.getSceneInstIds()) {
                    // 调用一下此方法确保场景实例的数据在缓存中(如果缓存中没有会从数据库恢复)
                    querySceneInstService.getSceneInst(sceneInstId, orderRequest.getCustId());
                }
            }

            OrderBusinessFactory.doHandle(orderRequest);
        }
        catch (Exception e) {
            kiteOrderAcceptLog.setErrStackInfo(ExceptionUtils.getStackTrace(e));
            if (e instanceof BssException) {
                kiteOrderAcceptLog.setResultCode(((BssException) e).getFailCode());
            }
            else {
                kiteOrderAcceptLog.setResultCode(ErrorConsts.ACCEPT_ERROR.getCode());
            }
            kiteOrderAcceptLog.setResultMsg(e.getMessage());
            throw e;
        }
        finally {
            recordKiteOrderAcceptLog(orderRequest, kiteOrderAcceptLog);
        }
    }

    /**
     * 记录极简转单受理日志
     * @param orderRequest
     * @param kiteOrderAcceptLog
     */
    private void recordKiteOrderAcceptLog(OrderRequest orderRequest, KiteOrderAcceptLog kiteOrderAcceptLog) {
        // 这里1为全记，2不记，其他报错才记
        String value = DcSystemParamCache.getDcParamVal(KeyConsts.RECORD_KITE_ACCEPT_LOG_MODE);
        if (KeyConsts.RECORD_ACCEPT_LOG_MODE_ALL.equals(value)) {
            asyncInsertLog(orderRequest, kiteOrderAcceptLog);
            return;
        }
        if (KeyConsts.RECORD_ACCEPT_LOG_MODE_NONE.equals(value)) {
            return;
        }
        if (!KeyConsts.SUCCESS_0.equals(kiteOrderAcceptLog.getResultCode())) {
            asyncInsertLog(orderRequest, kiteOrderAcceptLog);
        }
    }

    /**
     * 异步调用日志入库
     * @param orderRequest
     * @param kiteOrderAcceptLog
     */
    private void asyncInsertLog(OrderRequest orderRequest, KiteOrderAcceptLog kiteOrderAcceptLog) {
        CompletableFuture.runAsync(() -> {
            SpringUtil.getBean(KiteOrderAcceptService.class).insertLog(orderRequest, kiteOrderAcceptLog);
        });
    }

    /**
     * 日志入库
     * @param orderRequest
     * @param kiteOrderAcceptLog
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void insertLog(OrderRequest orderRequest, KiteOrderAcceptLog kiteOrderAcceptLog) {
        kiteOrderAcceptLog.setCustId(orderRequest.getCurrentCustId());
        kiteOrderAcceptLog.setStaffId(orderRequest.getStaffId());
        kiteOrderAcceptLog.setOrgId(orderRequest.getOrgId());
        kiteOrderAcceptLog.setRspTime(LocalDateTime.now());
        kiteOrderAcceptLog.setCustOrderId(orderRequest.getCustOrderId());
        if (StringUtils.isBlank(kiteOrderAcceptLog.getTransactionId())) {
            kiteOrderAcceptLog.setTransactionId(TransactionIdUtils.getTransactionIdOrRandom());
        }
        if (CollectionUtils.isNotEmpty(orderRequest.getGroupInstContainer().getShoppingCartGroupInsts())) {
            kiteOrderAcceptLog.setShoppingCartSerial(
                orderRequest.getGroupInstContainer().getShoppingCartGroupInsts().get(0).getShoppingCartSerial());
        }
        OrderRequestLog orderRequestLog = new OrderRequestLog();
        KiteBeanUtils.copyProperties(orderRequest, orderRequestLog);
        kiteOrderAcceptLog.setOrderRequestInfo(JSON.toJSONString(orderRequestLog));
        kiteOrderAcceptLog.setInvokeTrace(orderRequest.getHandlerClassNames().toString());
        kiteOrderAcceptLog.setLogId(SeqUtils.getNext(TableConsts.KiteOrderAcceptLog));
        KiteOrderAcceptLogMapper kiteOrderAcceptLogMapper = SpringUtil.getBean(KiteOrderAcceptLogMapper.class);
        kiteOrderAcceptLogMapper.insert(kiteOrderAcceptLog);
    }

    /**
     * Description: <br>
     * 删除场景实例缓存
     * @taskId <br>
     * @param orderRequests <br>
     */
    public void deleteSceneInsts(List<OrderRequest> orderRequests) {
        for (OrderRequest orderRequest : orderRequests) {
            orderRequest.getSceneInstIds().stream().forEach(sceneInstId -> {
                operateSceneInstService.deleteSceneInst(sceneInstId, orderRequest.getCustId());
            });
        }
    }

    /**
     * 校验并补充请求对象属性值
     * @param request
     */
    @SuppressWarnings("deprecation")
    private void checkOrderCommitRequest(OrderCommitRequestDTO request) {
        if (Objects.isNull(request)) {
            return;
        }

        SimpleLoginInfo simpleLoginInfo = ContextUtil.getSimpleLoginInfo();
        Assert.hasText(request.getCustId(), "custId can not be empty");
        if (StringUtils.isBlank(request.getStaffId())) {
            request.setStaffId(String.valueOf(simpleLoginInfo.getStaffId()));
        }
        if (StringUtils.isBlank(request.getOrgId())) {
            request.setOrgId(String.valueOf(simpleLoginInfo.getOrgId()));
        }
        if (StringUtils.isBlank(request.getPostId())) {
            request.setPostId(String.valueOf(simpleLoginInfo.getPostId()));
        }
        if (StringUtils.isBlank(request.getRegionId())) {
            request.setRegionId(String.valueOf(ContextUtil.getLoginInfo().getUserInfo().getPostRegionId()));
        }
        if (StringUtils.isBlank(request.getLanId())) {
            request.setLanId(simpleLoginInfo.getLanId());
        }
        if (StringUtils.isBlank(request.getStaffCode())) {
            request.setStaffCode(simpleLoginInfo.getStaffCode());
        }
    }
}
